package nl.utwente.csc.obsl.transformation;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.m2m.qvt.oml.BasicModelExtent;
import org.eclipse.m2m.qvt.oml.ExecutionContextImpl;
import org.eclipse.m2m.qvt.oml.ExecutionDiagnostic;
import org.eclipse.m2m.qvt.oml.ModelExtent;
import org.eclipse.m2m.qvt.oml.TransformationExecutor;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.progress.IProgressService;

public class OntoUML2OBSLHandler extends AbstractHandler {

	@Override
	public Object execute(ExecutionEvent event) throws ExecutionException {
		ISelection sel = HandlerUtil.getActiveMenuSelection(event);
		IStructuredSelection selection = (IStructuredSelection) sel;
		final Object firstElement = selection.getFirstElement();
		final ResourceSet resourceSet = new ResourceSetImpl();
		final IFile sourceFile = (IFile) firstElement;
		IProgressService progressService = PlatformUI.getWorkbench()
				.getProgressService();
		try {
			progressService.busyCursorWhile(new IRunnableWithProgress() {
				public void run(IProgressMonitor monitor) {

					// Refer to an existing transformation via URI
					URI transformationURI = URI
							.createURI("platform:/plugin/nl.utwente.csc.obsl.transformation.ontouml2obsl/transform/OntoUML2OBSL.qvto");
					// create executor for the given transformation
					TransformationExecutor executor = new TransformationExecutor(
							transformationURI);

					Resource inResource = resourceSet.getResource(
							URI.createFileURI(sourceFile.getLocation()
									.toString()), true);

					try {
						inResource.load(sourceFile.getContents(),
								new HashMap<Object, Object>());
					} catch (IOException | CoreException e1) {
						IStatus status = new Status(IStatus.ERROR,
								OntoUML2OBSLActivator.PLUGIN_ID, e1
										.getMessage(), e1);
						OntoUML2OBSLActivator.getDefault().getLog().log(status);
						return;
					}
					EList<EObject> inObjects = inResource.getContents();

					// create the input extent with its initial contents
					ModelExtent input = new BasicModelExtent(inObjects);
					// create an empty extent to catch the output
					ModelExtent output = new BasicModelExtent();

					// setup the execution environment details ->
					// configuration properties, logger, monitor object etc.
					ExecutionContextImpl context = new ExecutionContextImpl();
					context.setConfigProperty("keepModeling", true);
					context.setProgressMonitor(monitor);

					// run the transformation assigned to the executor with the
					// given
					// input and output and execution context ->
					// ChangeTheWorld(in, out)
					// Remark: variable arguments count is supported
					ExecutionDiagnostic result = executor.execute(context,
							input, output);

					// check the result for success
					if (result.getSeverity() == Diagnostic.OK) {
						// the output objects got captured in the output extent
						List<EObject> outObjects = output.getContents();

						try {
							String newPath = sourceFile.getLocation()
									.toString().replace(".refontouml", ".obsl");
							Resource outResource = resourceSet
									.createResource(URI.createFileURI(newPath));
							outResource.getContents().addAll(outObjects);
							outResource.save(Collections.emptyMap());
							sourceFile.getProject().refreshLocal(
									IResource.DEPTH_INFINITE, monitor);
						} catch (Exception e) {
							IStatus status = new Status(IStatus.ERROR,
									OntoUML2OBSLActivator.PLUGIN_ID, e
											.getMessage(), e);
							OntoUML2OBSLActivator.getDefault().getLog()
									.log(status);
						}

					} else {
						// turn the result diagnostic into status and send it to
						// error log
						IStatus status = BasicDiagnostic.toIStatus(result);
						OntoUML2OBSLActivator.getDefault().getLog().log(status);
					}
				}
			});
		} catch (Exception e) {
			IStatus status = new Status(IStatus.ERROR,
					OntoUML2OBSLActivator.PLUGIN_ID, e.getMessage(), e);
			OntoUML2OBSLActivator.getDefault().getLog().log(status);
		}
		return null;
	}

}
